package com.giantlizard.cloud.gateway.filter;

import com.giantlizard.cloud.base.generics.R;
import com.giantlizard.cloud.common.security.constants.SecurityConstants;
import com.giantlizard.cloud.common.security.model.LoginUser;
import com.giantlizard.cloud.common.security.service.TokenService;
import com.giantlizard.cloud.gateway.config.properties.IgnoreWhiteProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.web.server.SecurityWebFiltersOrder;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;

/**
 * 网关鉴权过滤器
 * 
 * @author GiantLizard
 */
@Component
@Slf4j
public class AuthFilter implements WebFilter, GlobalFilter, Ordered {

    @Autowired
    private IgnoreWhiteProperties ignoreWhite;  // 白名单配置
    
    @Autowired
    private TokenService tokenService;
    
    private final AntPathMatcher pathMatcher = new AntPathMatcher();

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        return doFilter(exchange, () -> chain.filter(exchange));
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        return doFilter(exchange, () -> chain.filter(exchange));
    }

    private Mono<Void> doFilter(ServerWebExchange exchange, FilterContinuation continuation) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        String path = request.getURI().getPath();

        // 白名单路径，直接放行
        if (StringUtils.hasText(path) && isWhitePath(path)) {
            return continuation.continue_();
        }
        
        // 获取token并校验
        String token = getToken(request);
        if (!StringUtils.hasText(token)) {
            return unauthorizedResponse(response, "令牌不能为空");
        }
        
        // 获取用户信息
        LoginUser loginUser = tokenService.getLoginUser(token);
        if (loginUser == null) {
            return unauthorizedResponse(response, "令牌已过期或验证不正确！");
        }
        
        // 验证token有效期
        if (tokenService.verifyToken(loginUser)) {
            return unauthorizedResponse(response, "令牌已过期！");
        }

        // 校验用户权限
        if (!hasPermission(loginUser, path)) {
            return forbiddenResponse(response, "没有访问该接口的权限");
        }

        // 创建认证对象
        Authentication authentication = new UsernamePasswordAuthenticationToken(
            loginUser, null, Collections.emptyList());

        // 将认证信息放入上下文
        return continuation.continue_()
            .contextWrite(ReactiveSecurityContextHolder.withAuthentication(authentication));
    }

    @FunctionalInterface
    private interface FilterContinuation {
        Mono<Void> continue_();
    }

    /**
     * 判断是否为白名单路径
     */
    private boolean isWhitePath(String path) {
        return ignoreWhite.getWhites().stream()
                .anyMatch(pattern -> pathMatcher.match(pattern, path));
    }

    /**
     * 获取请求头中的token
     */
    private String getToken(ServerHttpRequest request) {
        String token = request.getHeaders().getFirst(SecurityConstants.AUTHENTICATION);
        if (StringUtils.hasText(token) && token.startsWith(SecurityConstants.PREFIX)) {
            token = token.substring(SecurityConstants.PREFIX.length());
        }
        return token;
    }

    /**
     * 校验用户是否有权限访问当前接口
     */
    private boolean hasPermission(LoginUser loginUser, String requestPath) {
        // 获取用户权限列表
        List<String> permissions = loginUser.getPermissions();
        if (permissions == null || permissions.isEmpty()) {
            return false;
        }

        // 使用AntPathMatcher匹配权限
        return permissions.stream()
                .anyMatch(permission -> pathMatcher.match(permission, requestPath));
    }


    /**
     * 返回未授权响应
     */
    private Mono<Void> unauthorizedResponse(ServerHttpResponse response, String msg) {
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        return writeErrorResponse(response, msg);
    }

    /**
     * 返回禁止访问响应
     */
    private Mono<Void> forbiddenResponse(ServerHttpResponse response, String msg) {
        response.setStatusCode(HttpStatus.FORBIDDEN);
        return writeErrorResponse(response, msg);
    }

    /**
     * 写入错误响应
     */
    private Mono<Void> writeErrorResponse(ServerHttpResponse response, String msg) {
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        R<?> result = R.error(msg);
        byte[] bytes = result.toString().getBytes(StandardCharsets.UTF_8);
        return response.writeWith(Mono.just(response.bufferFactory().wrap(bytes)));
    }

    @Override
    public int getOrder() {
        // 确保在Spring Security过滤器之前执行
        return SecurityWebFiltersOrder.AUTHENTICATION.getOrder() - 1;
    }
} 